package edu.task.snake.controller;


import edu.task.snake.model.Cell;
import edu.task.snake.model.Frog;
import edu.task.snake.model.Snake;
import edu.task.snake.model.SnakeElement;
import edu.task.snake.model.arena.ArenaGrid;
import edu.task.snake.view.FrogRender;
import edu.task.snake.view.SnakeRender;
import edu.task.snake.view.View;
import edu.task.snake.view.ViewArena;

import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

public class GameEngine {

    SnakeElement snakeHead;

    private int cellWidth;
    private int cellHeight;
    private int snakeSize;
    private int frogCount;
    private static int cellSizePixel;

    private ArenaGrid arena;
    private View view;
    private List<Frog> frogList; //ToDo
    private List<FrogController> frogControllerList;
    private List<FrogRender> frogRenderList;
    private SnakeRender snakeRender;
    private Snake snake;
    private SnakeController snakeController;
    //Begin merge
    private boolean inGame = true;

    private Object lock = new Object();

    public GameEngine(int cellWidth, int cellHeight, int snakeSize, int frogCount, int cellSizePixel) {
        this.cellSizePixel = cellSizePixel;
        this.cellWidth = cellWidth;
        this.cellHeight = cellHeight;
        this.snakeSize = snakeSize;
        this.frogCount = frogCount;
        frogList = new ArrayList<Frog>();
        frogControllerList = new ArrayList<FrogController>();
        frogRenderList = new ArrayList<FrogRender>();
        initGameEngine();
    }

    private void initGameEngine() {
        this.arena = new ArenaGrid(cellWidth, cellHeight);
        view = new View(cellSizePixel, this);
        initSnake();
        int count = frogCount;
        while (count > 0) {
            initFrog();
            count--;
        }
        ((ViewArena) view.getArenaPanel()).setFrogRenderList(frogRenderList);
        view.repaint();
        view.setVisible(true);
        for (FrogController controller : frogControllerList) {
            controller.start();
        }
        snakeController.start();

    }


    private void initSnake() {
        snakeHead = new SnakeElement(0, 0);
        arena.setToArena(0, 0, snakeHead);
        for (int i = 1; i < snakeSize; i++) {
            SnakeElement newSnakeElement = new SnakeElement(i, 0);
            arena.setToArena(i, 0, newSnakeElement);
            snakeHead.addPreviosly(newSnakeElement); //ToDo if arena width less then snake width??
            snakeHead = newSnakeElement;
//    ToDO        Check arena cell empty??  ========
            //ToDO Merge
            snake = new Snake();
            ArrayList<Cell> cells = new ArrayList<Cell>();
            cells.add(new Cell(1, 0)); //initialise with params
            cells.add(new Cell(2, 0));
            cells.add(new Cell(3, 0));
            snake.setArrayList(cells);
            snake.addActionListener((ViewArena) view.getArenaPanel());
            snakeRender = new SnakeRender(view.getArenaPanel(), snake);
            ((ViewArena) view.getArenaPanel()).setSnakeRender(snakeRender);
            snakeController = new SnakeController(snake, this);
            view.getArenaPanel().addKeyListener(new KAdapter(snakeController)); //todo Not Working???
            view.getArenaPanel().addMouseListener(new MAdapter(snakeController));
            //End Merge ToDO
        }
    }

    public Frog initFrog() {
        boolean correctInit = true;
        while (correctInit) {
            int randomWidth = (int) (Math.random() * cellWidth);
            int randomHeight = (int) (Math.random() * cellHeight);
            if (arena.getFromArena(randomWidth, randomHeight) == null) {  // todo check arena cell empty
                Frog frog = new Frog(randomWidth, randomHeight);
                arena.setToArena(randomWidth, randomHeight, frog);
                frog.addActionListener((ViewArena) view.getArenaPanel());
                frogList.add(frog);
                FrogController frogController = new FrogController(frog, this);
                frogControllerList.add(frogController);
                FrogRender frogRender = new FrogRender(view.getArenaPanel(), frog);
                frogRenderList.add(frogRender);
                correctInit = false;
                return frog;
            }
        }
        return null;
    }

    public View getView() {
        return view;
    }

    public int getCellWidth() {
        return cellWidth;
    }

    public int getCellHeight() {
        return cellHeight;
    }

    public int getSnakeSize() {
        return snakeSize;
    }

    public int getFrogCount() {
        return frogCount;
    }

    public ArenaGrid getArena() {
        return arena;
    }

    public Object getLock() {
        return lock;
    }

    public static int getCellSizePixel() {
        return cellSizePixel;
    }

    public boolean isInGame() {
        return inGame;
    }

    public void setInGame(boolean inGame) {
        this.inGame = inGame;
    }

    public List<Frog> getFrogList() {
        return frogList;
    }

    public void checkFreeSpace() {

    }

    public void stopGame() {

       snakeController.interrupt();

        for (FrogController controller : frogControllerList) {
            while (!controller.isInterrupted()) {
                controller.interrupt();
//                controller.stop();
            }//todo http://stackoverflow.com/questions/4705709/various-way-to-stop-a-thread-which-is-the-correct-way
//            controller.stop();
        }

        ((ViewArena) view.getArenaPanel()).gameOver();


    }

    public void killFrogProcess() {
    }
}
